package com.api.tournament.service.impl;

import com.api.common.JSONUtils;
import com.api.common.mybatis.ResultMap;
import com.api.core.ServiceException;
import com.api.core.config.AuthUser;
import com.api.core.response.Result;
import com.api.core.response.ResultGenerator;
import com.api.core.service.AbstractService;
import com.api.tournament.contonst.Const;
import com.api.tournament.dao.*;
import com.api.tournament.model.*;
import com.api.tournament.queue.TournamentStartDelayedMessage;
import com.api.tournament.queue.TournamentStartDelayedService;
import com.api.tournament.service.TournamentService;
import com.api.tournament.vo.*;
import com.api.user.dao.GameMapper;
import com.api.user.dao.GameProfileMapper;
import com.api.user.dao.ManageInfoMapper;
import com.api.user.dao.UserInfoMapper;
import com.api.user.model.*;
import com.api.user.service.CoinTransactionService;
import com.api.user.service.TaskService;
import com.api.user.service.TeamService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static com.api.tournament.contonst.Const.*;

/**
 * Created by wanghuiwen on 2021/03/23.
 */
@Service
@Transactional
public class TournamentServiceImpl extends AbstractService<Tournament> implements TournamentService {

    Logger logger = LoggerFactory.getLogger(this.getClass());
    @Resource
    private TournamentMapper tournamentMapper;
    @Resource
    private TournamentRewardMapper tournamentRewardMapper;
    @Resource
    private TournamentSponsorMapper tournamentSponsorMapper;
    @Resource
    private StageMapper stageMapper;
    @Resource
    private RoundMapper roundMapper;
    @Resource
    private TournamentIntroductionMapper tournamentIntroductionMapper;
    @Resource
    private TournamentTermsMapper tournamentTermsMapper;
    @Resource
    private TeamService teamService;
    @Resource
    private TournamentTeamMapper tournamentTeamMapper;
    @Resource
    private TournamentTeamUserMapper tournamentTeamUserMapper;
    @Resource
    private TournamentProfileMapper tournamentProfileMapper;
    @Resource
    private UserInfoMapper userInfoMapper;
    @Resource
    private CoinTransactionService coinTransactionService;
    @Resource
    private RoundLogMapper roundLogMapper;
    @Resource
    private StageRankMapper stageRankMapper;
    @Resource
    private TournamentExamineLogMapper tournamentExamineLogMapper;
    @Resource
    private GameMapper gameMapper;
    @Resource
    private WithdrawalMapper withdrawalMapper;
    @Resource
    private TournamentRewardUserMapper tournamentRewardUserMapper;
    @Resource
    private ManageInfoMapper manageInfoMapper;
    @Resource
    private TaskService taskService;
    @Resource
    private TournamentStartDelayedService tournamentStartDelayedService;
    @Resource
    private GameProfileMapper gameProfileMapper;

    @Override
    public Result list(Integer state, String tournamentName, Integer tournamentType, Boolean hot, Long gameId, String tournamentCategory, Long createUser, Integer format, String order, Integer page, Integer size, AuthUser user) {

        Map<String, Object> orderParams = JSONUtils.json2map(order);
        for (String key : orderParams.keySet()) {
            if (orderParams.get(key) != null && orderParams.get(key).equals("ascending")) orderParams.put(key, "asc");
            if (orderParams.get(key) != null && orderParams.get(key).equals("descending")) orderParams.put(key, "desc");
        }
        Map<String,Object> params = new HashMap<>();

        if(user.getType()== USER_ORGANIZATION){
            ManageInfo manageInfo = manageInfoMapper.selectByPrimaryKey(user.getId());
            params.put("userId",manageInfo.getOrganizer());
        }else {
            params.put("userId",createUser);
        }
        PageHelper.startPage(page, size);
        params.put("state",state);
        params.put("tournamentName",tournamentName);
        params.put("tournamentType",tournamentType);
        params.put("hot",hot);
        params.put("gameId",gameId);
        params.put("order",order);
        params.put("tournamentCategory",tournamentCategory);
        params.put("format",format);

        orderParams.put("hot","desc");
        orderParams.put("id","desc");
        List<TournamentListVo> res = tournamentMapper.list(params,orderParams);

        PageInfo<TournamentListVo> pageInfo = new PageInfo<>(res);
        return ResultGenerator.genSuccessResult(pageInfo);
    }

    @Override
    public Result add(TournamentAdd tournamentAdd, AuthUser user) {
        if (!tournamentAdd.getRegisteryFeeType().equals(REGISTER_FEE_TYPE_POINT) && !tournamentAdd.getRegisteryFeeType().equals(REGISTER_FEE_TYPE_COIN)) {
            return ResultGenerator.genFailResult(400,"Register Fee Type error");
        }
        if(tournamentAdd.getParticipantsSize() > 256) {
            return ResultGenerator.genFailResult(400,"Maximum number of participants are 256");
        }
        Tournament sameName =  findBy("tournamentName",tournamentAdd.getTournamentName());
        if(sameName!=null&& !sameName.getId().equals(tournamentAdd.getTournamentId())){
            return  ResultGenerator.genFailResult(400,"Event name already exists");
        }

        Tournament tournament = new Tournament();
        tournament.setEastWest(tournamentAdd.getEastWest());
        tournament.setGameId(tournamentAdd.getGameId());
        tournament.setLiveUrl(tournamentAdd.getLiveUrl());
        tournament.setOku(tournamentAdd.getOku());
        tournament.setParticipantsSize(tournamentAdd.getParticipantsSize());
        tournament.setRegisteryFee(tournamentAdd.getRegisteryFee());
        tournament.setRegisteryFeeType(tournamentAdd.getRegisteryFeeType());
        tournament.setRegistrationTimeEnd(tournamentAdd.getRegistrationTimeEnd());
        tournament.setRegistrationTimeStart(tournamentAdd.getRegistrationTimeStart());
        tournament.setSite(tournamentAdd.getSite());
        tournament.setState(tournamentAdd.getState());
        tournament.setStudent(tournamentAdd.getStudent());
        tournament.setSubtitle(tournamentAdd.getSubtitle());
        tournament.setTournamentCover(tournamentAdd.getTournamentCover());
        tournament.setTournamentName(tournamentAdd.getTournamentName());
        tournament.setTournamentTime(tournamentAdd.getTournamentTime());
        tournament.setTournamentType(tournamentAdd.getTournamentType());
        tournament.setAuthentication(tournamentAdd.getAuthentication());
        tournament.setMode(tournamentAdd.getMode());
        tournament.setFaceBook(tournamentAdd.getFaceBook());
        tournament.setInstagram(tournamentAdd.getInstagram());
        tournament.setDiscord(tournamentAdd.getDiscord());
        tournament.setCompulsory(tournamentAdd.getCompulsory());
        tournament.setSubstitute(tournamentAdd.getSubstitute());
        if(tournamentAdd.getDraft()!=null&&tournamentAdd.getDraft()){
            tournament.setStatus(TOURNAMENT_STATUS_DRAFT);
        }else {
            tournament.setStatus(TOURNAMENT_STATUS_TODO);
        }
        if(tournamentAdd.getTournamentId()!=null){
            tournament.setId(tournamentAdd.getTournamentId());
            /**
             * 参赛者
             */
            List<TournamentUserVo> contestant ;
            if(tournamentAdd.getTournamentType()==0){
                contestant =  tournamentTeamMapper.selectByTournamentIdJoinUser(tournamentAdd.getTournamentId(),true);
            }else {
                contestant  = tournamentTeamMapper.selectByTournamentId(tournamentAdd.getTournamentId(), tournamentAdd.getTournamentType(),true);
            }
            if(contestant.size() > tournamentAdd.getParticipantsSize()){
                throw  new ServiceException("Already have"+contestant.size() +"participants");
            }
            update(tournament);
        }else {
            if(user.getType().equals(USER_ADMIN)){
                tournament.setTournamentCategory(TOURNAMENT_CATEGORY_OFFICIALLY);
                tournament.setCreateUser(user.getId());
            }
            if(user.getType().equals(USER_ORGANIZATION)){
                ManageInfo manageInfo = manageInfoMapper.selectByPrimaryKey(user.getId());
                tournament.setCreateUser(manageInfo.getOrganizer());
                tournament.setTournamentCategory(TOURNAMENT_CATEGORY_PRIVATELY);
            }
            tournament.setCreateTime(new Date().getTime());

            tournament.setExamine(TOURNAMENT_EXAMINE_TODO);
            tournament.setAuthenticationStatus(1);
            save(tournament);
        }
        //创建的时候添加
        if(user.getType().equals(USER_ORGANIZATION)&&tournamentAdd.getTournamentId() == null) {
            Withdrawal withdrawal = new Withdrawal();
            withdrawal.setTournamentId(tournament.getId());
            withdrawal.setUserId(user.getId());
            withdrawal.setOrganizationProfit(BigDecimal.ZERO);
            withdrawal.setStatus(1);
            withdrawalMapper.insert(withdrawal);
        }

        TournamentIntroduction introduction = new TournamentIntroduction();
        introduction.setIntroduction(tournamentAdd.getIntroduction());
        introduction.setTournamentId(tournament.getId());
        if(tournamentAdd.getTournamentId()!=null){
            tournamentIntroductionMapper.updateByPrimaryKey(introduction);
        }else {
            tournamentIntroductionMapper.insertSelective(introduction);
        }

        TournamentTerms terms = new TournamentTerms();
        terms.setTerms(tournamentAdd.getTerms());
        terms.setTournamentId(tournament.getId());
        if(tournamentAdd.getTournamentId()!=null){
            tournamentTermsMapper.updateByPrimaryKey(terms);
        }else {
            tournamentTermsMapper.insert(terms);
        }
        /**
         * 奖品
         */
        List<TournamentReward> rewards = new ArrayList<>();
        BigDecimal rewardAmount = new BigDecimal(0);
        for (int i = 0; i < tournamentAdd.getReward().size(); i++) {
            TournamentReward reward = new TournamentReward();
            reward.setRewardName(tournamentAdd.getReward().get(i).getRewardName());
            reward.setRewardPicture(tournamentAdd.getReward().get(i).getRewardPicture());
            reward.setRewardPrice(tournamentAdd.getReward().get(i).getRewardPrice());
            reward.setRewardType(tournamentAdd.getReward().get(i).getRewardType());
            reward.setRanking(tournamentAdd.getReward().get(i).getRank());
            reward.setTournamentId(tournament.getId());
            reward.setQuantity(tournamentAdd.getReward().get(i).getQuantity());
            reward.setRewardId(tournamentAdd.getReward().get(i).getRewardId());
            rewardAmount = rewardAmount.add(tournamentAdd.getReward().get(i).getRewardPrice().multiply(new BigDecimal(tournamentAdd.getReward().get(i).getQuantity())));
            rewards.add(reward);
        }
        tournament.setBonus(rewardAmount);
        tournamentMapper.updateByPrimaryKeySelective(tournament);
        if(tournamentAdd.getTournamentId()!=null){
            List<TournamentReward> order =  tournamentRewardMapper.selectByTournamentId(tournamentAdd.getTournamentId());
            List<TournamentReward> remove = order.stream().filter(tournamentReward -> !rewards.stream().map(TournamentReward::getRewardId).collect(Collectors.toList()).contains(tournamentReward.getRewardId())).collect(Collectors.toList());
            for (TournamentReward tournamentReward : remove) {
                tournamentRewardMapper.deleteByPrimaryKey(tournamentReward);
            }
            for (TournamentReward reward : rewards) {
                if(reward.getRewardId() !=null){
                    tournamentRewardMapper.updateByPrimaryKeySelective(reward);
                }else {
                    reward.setTournamentId(tournamentAdd.getTournamentId());
                    tournamentRewardMapper.insert(reward);
                }
            }
        }else {
            tournamentRewardMapper.insertList(rewards);
        }

        /**
         * 赞助商
         */
        List<TournamentSponsor> tournamentSponsors = new ArrayList<>();
        for (int i = 0; i < tournamentAdd.getSponsor().size(); i++) {
            TournamentSponsor tournamentSponsor = new TournamentSponsor();
            tournamentSponsor.setSponsorLogo(tournamentAdd.getSponsor().get(i).getSponsorLogo());
            tournamentSponsor.setSponsorName(tournamentAdd.getSponsor().get(i).getSponsorName());
            tournamentSponsor.setSponsorType(tournamentAdd.getSponsor().get(i).getSponsorType());
            tournamentSponsor.setTournamentId(tournament.getId());
            tournamentSponsor.setCompanyType(tournamentAdd.getSponsor().get(i).getCompanyType());
            tournamentSponsor.setSponsorId(tournamentAdd.getSponsor().get(i).getSponsorId());
            tournamentSponsors.add(tournamentSponsor);
        }
        if(tournamentAdd.getTournamentId()!=null){
            for (TournamentSponsor tournamentSponsor : tournamentSponsors) {
                tournamentSponsorMapper.updateByPrimaryKeySelective(tournamentSponsor);
            }
        }else {
            tournamentSponsorMapper.insertListNoAuto(tournamentSponsors);
        }

        /**
         * 阶段
         */
        if(tournamentAdd.getStage().size() > 1 && tournamentAdd.getStage().get(0).getGroupSize()<2){
            throw  new ServiceException("First stage's participants cannot less than 2 if the tournament has double stage");
        }

        /**
         * 修改的时候可能删除阶段
         */
        if(tournamentAdd.getTournamentId()!=null){
            List<Stage> stages = stageMapper.selectByTournamentId(tournamentAdd.getTournamentId());
            List<Stage> remove = stages.stream().filter(item -> !tournamentAdd.getStage().stream().map(TournamentAdd.StageBean::getId).collect(Collectors.toList()).contains(item.getId())).collect(Collectors.toList());
            for (Stage removeStage : remove) {
                stageMapper.deleteByPrimaryKey(removeStage);
            }
        }

        for (int i = 0; i < tournamentAdd.getStage().size(); i++) {
            Stage stage = new Stage();
            stage.setBest(tournamentAdd.getStage().get(i).getBest());
            stage.setId(tournamentAdd.getStage().get(i).getId());
            stage.setFormat(tournamentAdd.getStage().get(i).getFormat());
            if(tournamentAdd.getStage().get(i).getFormat() == GAME_FORMAT_ROUND){
                if(tournamentAdd.getStage().get(i).getGroupSize() == 0){
                    throw new ServiceException("Every group cannot be 0");
                }
                if(tournamentAdd.getStage().get(i).getPromotionSize() == 0){
                    throw new ServiceException("Number of participants go to next stage cannot be 0");
                }
                if(tournamentAdd.getStage().get(i).getRound() == 0){
                    throw new ServiceException("Number of participants compete each other cannot be 0");
                }
                if( tournament.getParticipantsSize() < tournamentAdd.getStage().get(i).getGroupSize() * 2){
                    throw  new ServiceException("Number of participants cannot less than "+ tournamentAdd.getStage().get(i).getGroupSize() * 2);
                }
            }
            stage.setPromotionSize(tournamentAdd.getStage().get(i).getPromotionSize());
            stage.setGroupSize(tournamentAdd.getStage().get(i).getGroupSize());
            stage.setRound(tournamentAdd.getStage().get(i).getRound());
            stage.setStageType(tournamentAdd.getStage().get(i).getStageType());
            stage.setTournamentId(tournament.getId());
            stage.setStageType(i<tournamentAdd.getStage().size() ? "" : "");
            if(tournamentAdd.getTournamentId()!=null){
                if(stage.getId()!=null&&stage.getId()!=0){
                    stageMapper.updateByPrimaryKeySelective(stage);
                }else {
                    stageMapper.insertSelective(stage);
                }
            }else {
                stageMapper.insertSelective(stage);
            }
        }

        /**
         * 加入提醒队列
         */
        if(tournamentAdd.getTournamentId()!=null){
            if(tournament.getTournamentTime()!=null && tournament.getTournamentTime() > System.currentTimeMillis()){
                TournamentStartDelayedMessage message = new TournamentStartDelayedMessage();
                //提前30分钟
                message.setStartDate(tournament.getTournamentTime()-1800000);
                message.setTournamentId(tournament.getId());
                message.setTournamentName(tournament.getTournamentName());
                tournamentStartDelayedService.offer(message);
            }
        }

        return ResultGenerator.genSuccessResult(tournament.getId());
    }

    @Override
    public Result detail(Long id, Boolean isCheckIn) {
        TournamentDetail detail = new TournamentDetail();
        Tournament tournament = findById(id);
        detail.setEastWest(tournament.getEastWest());
        detail.setAuthentication(tournament.getAuthentication());
        detail.setGameId(tournament.getGameId());
        detail.setLiveUrl(tournament.getLiveUrl());
        detail.setOku(tournament.getOku());
        detail.setParticipantsSize(tournament.getParticipantsSize());
        detail.setRegisteryFee(tournament.getRegisteryFee());
        detail.setRegisteryFeeType(tournament.getRegisteryFeeType());
        detail.setRegistrationTimeEnd(tournament.getRegistrationTimeEnd());
        detail.setRegistrationTimeStart(tournament.getRegistrationTimeStart());
        detail.setSite(tournament.getSite());
        detail.setState(tournament.getState());
        detail.setStudent(tournament.getStudent());
        detail.setSubtitle(tournament.getSubtitle());
        detail.setTournamentCategory(tournament.getTournamentCategory());
        detail.setTournamentCover(tournament.getTournamentCover());
        detail.setId(tournament.getId());
        detail.setTournamentName(tournament.getTournamentName());
        detail.setTournamentTime(tournament.getTournamentTime());
        detail.setTournamentType(tournament.getTournamentType());
        detail.setStatus(tournament.getStatus());
        detail.setMode(tournament.getMode());
        detail.setFaceBook(tournament.getFaceBook());
        detail.setInstagram(tournament.getInstagram());
        detail.setDiscord(tournament.getDiscord());
        detail.setSubstitute(tournament.getSubstitute());
        detail.setCompulsory(tournament.getCompulsory());
        Game game = gameMapper.selectByPrimaryKey(tournament.getGameId());
        detail.setGameName(game.getGameName());


        TournamentIntroduction introduction = tournamentIntroductionMapper.selectByPrimaryKey(tournament.getId());
        if (introduction != null) {
            detail.setIntroduction(introduction.getIntroduction());
        }

        TournamentTerms terms = tournamentTermsMapper.selectByPrimaryKey(tournament.getId());
        if (terms != null) {
            detail.setTerms(terms.getTerms());
        }

        List<TournamentReward> rewards = tournamentRewardMapper.selectByTournamentId(id);
        if (rewards != null) {
            detail.setRewards(rewards);
        }

        List<TournamentSponsor> sponsors = tournamentSponsorMapper.selectByTournamentId(id);
        if (sponsors != null) {
            detail.setSponsors(sponsors);
        }
        List<StageVo> stages;
        if(tournament.getTournamentType()==0){
            stages = stageMapper.selectVoByTournamentIdJoinUser(id);
        }else {
            stages = stageMapper.selectVoByTournamentId(id);
        }

        if (stages != null) {
            detail.setStages(stages);
        }

        List<TournamentUserVo> contestant ;

        if(tournament.getTournamentType()==0){
            contestant =  tournamentTeamMapper.selectByTournamentIdJoinUser(id,isCheckIn);
        }else {
            contestant  = tournamentTeamMapper.selectByTournamentId(id, tournament.getTournamentType(),isCheckIn);
        }
        if (contestant != null) {
            detail.setContestant(contestant);
        }
        List<TournamentExamineLog> tournamentExamineLogs = tournamentExamineLogMapper.list(tournament.getId());
        detail.setExamineLogs(tournamentExamineLogs);

        if(tournament.getTournamentCategory().equals(TOURNAMENT_CATEGORY_PRIVATELY)){
            ResultMap<String,Object> res =  tournamentMapper.organizer(tournament.getCreateUser());
            detail.setOrganizer(res);
        }

        return ResultGenerator.genSuccessResult(detail);
    }

    @Override
    public Result rewardConfirm(Long rewardId, Boolean confirm) {
        TournamentReward reward = tournamentRewardMapper. selectByPrimaryKey(rewardId);
        reward.setRewardConfirm(confirm);
        tournamentRewardMapper.updateByPrimaryKeySelective(reward);
        List<TournamentReward> rewards = tournamentRewardMapper.selectByTournamentId(reward.getTournamentId());
        Tournament tournament = findById(reward.getTournamentId());
        if (rewards != null) {
            for (TournamentReward tournamentReward : rewards) {
                if (!tournamentReward.getRewardConfirm()) {
                    tournament.setAuthenticationStatus(1);
                    update(tournament);
                    break;
                }
                tournament.setAuthenticationStatus(2);
                update(tournament);

            }
        }
        return ResultGenerator.genSuccessResult();
    }

    @Override
    public Result review(Long tournamentId, Integer examine, String reason, AuthUser authUser) {

        TournamentExamineLog examineLog = new TournamentExamineLog();
        examineLog.setAuthenticationId(tournamentId);
        examineLog.setCreateDate(new Date().getTime());
        examineLog.setStatus(examine);
        examineLog.setUserId(authUser.getId());
        examineLog.setReason(reason);
        tournamentExamineLogMapper.insertSelective(examineLog);

        Tournament tournament = findById(tournamentId);
        tournament.setExamine(examine);
        if (examine == Const.TOURNAMENT_EXAMINE_AGREE) {
            tournament.setStatus(Const.TOURNAMENT_STATUS_SIGN);
        }

        if (examine == Const.TOURNAMENT_EXAMINE_REFUSE) {
            if(reason == null){
                return ResultGenerator.genFailResult(400,"Please fill in the reason for rejection");
            }
            tournament.setStatus(Const.TOURNAMENT_STATUS_REFUSE);

        }
        update(tournament);
        return ResultGenerator.genSuccessResult();
    }

    @Override
    public Result signup(Long tournamentId, Long teamId, AuthUser user, String[] userId) {
        List<TournamentTeam> tournamentUsers = tournamentTeamMapper.findByTournamentId(tournamentId,true);

        TournamentProfile profile = tournamentProfileMapper.selectByPrimaryKey(TOURNAMENT_PROFILE_ID);
        Tournament tournament = tournamentMapper.selectByPrimaryKey(tournamentId);

        if(tournamentUsers.size()>tournament.getParticipantsSize()){
            return ResultGenerator.genFailResult(400,"The number of participants is full");
        }

        if(tournament.getRegistrationTimeEnd() < new Date().getTime()){
            return ResultGenerator.genFailResult(400,"Exceeded the registration time");
        }

        List<GameProfile> profiles = gameProfileMapper.findByUserId(user.getId());
        if(profiles==null || profiles.size()<1){
            return  ResultGenerator.genFailResult(400,"first add game Profile");
        }

        /**
         * 1. Able to join free government tournaments ONLY
         * 只可以参与政府机构赛事
         *
         * 4. Able to join FREE rapid challenge
         * 只可以参加免费的对打
         */
        if(user.getLevel().equals(USER_LEVEL_BASE)){
            if(tournament.getRegisteryFee().compareTo(BigDecimal.ZERO) > 0 ){
                return ResultGenerator.genFailResult(400,"You can only join free rapid challenge");
            }

            if(!tournament.getTournamentCategory().equals(TOURNAMENT_CATEGORY_OFFICIALLY)){
                return ResultGenerator.genFailResult(400,"Your membership allow you to join only Bountee's free tournament. You can upgrade your membership to join this tournament.");
            }
        }

        if(tournament.getMode()!=null&& tournament.getMode() > userId.length){
            return ResultGenerator.genFailResult(400,"The number of participants should min "+ tournament.getMode());
        }

        /**
         * 必须替补
         */
        if(tournament.getSubstitute()!=null && tournament.getCompulsory()!=null && tournament.getCompulsory()  && (tournament.getMode() + tournament.getSubstitute()) != userId.length){
            return ResultGenerator.genFailResult(400,"The number of participants should be "+ tournament.getMode() + " and substitute  should be " + tournament.getSubstitute());
        }
        /**
         * 非必需替补
         */

        if(tournament.getSubstitute()!=null && tournament.getCompulsory()!=null && !tournament.getCompulsory()  && tournament.getSubstitute() < (userId.length - tournament.getMode())){
            return ResultGenerator.genFailResult(400,"The number of participants should max "+ tournament.getMode() + " and substitute  should max " + tournament.getSubstitute());
        }
        /**
         * 不需要替补
         */
        if((tournament.getSubstitute()==null || tournament.getSubstitute() <1) && tournament.getMode()!=null && tournament.getMode() != userId.length){

            return ResultGenerator.genFailResult(400,"The number of participants should be "+ tournament.getMode());
        }

        List<TournamentTeam>  teamUser = tournamentTeamMapper.selectByTeamId(teamId,tournamentId,true);

        if(teamUser!=null&& teamUser.size() > 0){
            throw  new ServiceException("You have registered this tournament, cannot register again");
        }
        TournamentTeam tournamentTeam = new TournamentTeam();
        tournamentTeam.setTournamentId(tournamentId);
        if(tournament.getTournamentType()==0){
            tournamentTeam.setTeamId(Long.valueOf(userId[0]));
            tournamentTeam.setLeaderId(Long.valueOf(userId[0]));
        }else {
            tournamentTeam.setTeamId(teamId);
            Team team =  teamService.findById(teamId);
            if(!Objects.equals(team.getLeaderId(), user.getId())){
                throw  new ServiceException("You are not the leader of the team");
            }
            tournamentTeam.setLeaderId(team.getLeaderId());
        }
        tournamentTeam.setSignupTime(new Date().getTime());
        tournamentTeamMapper.insert(tournamentTeam);


        /**
         * 遍历报名用户
         */
        for (int i = 0; i <userId.length ; i++) {
            TournamentTeamUser tournamentTeamUser = new TournamentTeamUser();
            tournamentTeamUser.setTournamentTeamId(tournamentTeam.getTournamentUserId());
            tournamentTeamUser.setUserId(Long.parseLong(userId[i]));

            TournamentTeamUser users = tournamentTeamUserMapper.selectByUidAndTournamentId(Long.parseLong(userId[i]),tournamentId);
            UserInfo info =  userInfoMapper.selectByPrimaryKey(userId[i]);

            if(tournament.getOku()!=null&&tournament.getOku()&&(info.getOku()==null||!info.getOku())){
                throw  new ServiceException(info.getFullName() + " This tournament open only for OKU");
            }
            if(tournament.getStudent()!=null&&tournament.getStudent()){
                ResultMap<String,Object> identification= tournamentMapper.findIdentificationByUserType(Long.parseLong(userId[i]),"student");
                if(identification==null){
                    throw  new ServiceException(info.getFullName() + " This tournament open only for Student");
                }
            }
            if(!StringUtils.isEmpty(tournament.getState())){
                if(info.getAddressState()==null||!info.getAddressState().equals(tournament.getState())){
                    throw  new ServiceException(info.getFullName() + "This tournament open only for "+tournament.getState());
                }
            }
            if(!StringUtils.isEmpty(tournament.getEastWest())){
                if(tournament.getEastWest().equals("east")&&!userIsEast(info)){
                    throw  new ServiceException(info.getFullName() + "This tournament open only for "+tournament.getEastWest());
                }
                if(tournament.getEastWest().equals("west")&&!userIsWest(info)){
                    throw  new ServiceException(info.getFullName() + "This tournament open only for "+tournament.getEastWest());
                }
            }
            if(users!=null){
                throw  new ServiceException(info.getFullName() + " You have registered this tournament, cannot register again.");
            }

            /**
             * 完成任务
             */
            taskService.completeTask("5",Long.parseLong(userId[i]),1);

            /**
             * 计算报名费 与手续费
             */
            BigDecimal registerFee = tournament.getRegisteryFee();
            BigDecimal handlingFee = new BigDecimal(0);

            //扣除报名费  只扣队长
            if (registerFee.compareTo(BigDecimal.ZERO) > 0 && info.getUserId().equals(user.getId())) {

                if (profile.getServiceChargeModel().equals(Const.SERVICE_CHARGE_MODEL_RATIO)) {
                    handlingFee = registerFee.multiply(profile.getServiceChargeRatio());
                }
                if (profile.getServiceChargeModel().equals(Const.SERVICE_CHARGE_MODEL_VALUE)) {
                    handlingFee = profile.getServiceChargeValue();
                }
                tournamentTeamUser.setHandlingFee(handlingFee);
                tournamentTeamUser.setRegisteryFee(registerFee);

                if (info.getCoin().compareTo(handlingFee.add(registerFee)) < 0) {
                    throw  new ServiceException(info.getFullName() + "Insufficient coin");
                } else {
                    // 添加交易记录 扣除费用
                    CoinTransaction transaction = new CoinTransaction();
                    transaction.setAmountBalance(handlingFee.add(registerFee).negate());
                    transaction.setFromUserId(Long.parseLong(userId[i]));
                    transaction.setOrderId(tournamentId);
                    transaction.setRemark("sign up");
                    transaction.setTransactionTime(new Date().getTime());
                    transaction.setTransactionType(COIN_TRANSACTION_TYPE_REGISTER);
                    transaction.setCreateId(Long.parseLong(userId[i]));
                    coinTransactionService.addOrSub(transaction);
                }
                //统计平台手续费
                tournament.setServiceProfit(tournament.getServiceProfit().add(handlingFee));
                //报名费收益
                tournament.setOrganizationProfit(tournament.getOrganizationProfit().add(registerFee));
                update(tournament);

            }else {
                tournamentTeamUser.setHandlingFee(new BigDecimal(0));
                tournamentTeamUser.setRegisteryFee(new BigDecimal(0));
            }
            tournamentTeamUserMapper.insert(tournamentTeamUser);
        }

        return ResultGenerator.genSuccessResult();
    }

    /**
     * 判断用户是否是东马
     * @param info
     * @return
     */
    private boolean userIsWest(UserInfo info) {
        return  true;
    }

    /**
     * 判断用户是否是西马
     * @param info
     * @return
     */
    private boolean userIsEast(UserInfo info) {
        return true;
    }


    /**
     * 结束报名 生成对战
     * @param tournamentId
     * @return
     */
    @Override
    public Result endRegistration(Long tournamentId) {
        Tournament tournament = findById(tournamentId);

        List<TournamentTeam> tournamentUsers = tournamentTeamMapper.findByTournamentId(tournamentId,false);

        if(tournamentUsers.size()<2) return  ResultGenerator.genFailResult(400,"Insufficient number or participants");

        List<Stage> stages = stageMapper.selectByTournamentId(tournamentId);

        if(stages.get(0).getEnd()!=null){
            throw  new ServiceException("Tournament has started, cannot amend.");
        }

        tournament.setStatus(3);
        tournamentMapper.updateByPrimaryKeySelective(tournament);

        for (int i = 0; i <stages.size() ; i++) {
            if(i==0){
                genRoundLog(tournament,stages.get(i),tournamentUsers);
            }else {
                List<TournamentTeam> tournamentUser = new ArrayList<>();
                //第二阶段参赛的人数
                int userSize = tournamentUsers.size() / stages.get(i-1).getGroupSize() * stages.get(i-1).getPromotionSize();
                for (int i1 = 0; i1 < userSize; i1++) {
                    tournamentUser.add(new TournamentTeam());
                }
                genRoundLog(tournament,stages.get(i),tournamentUser);
            }
        }

        return  ResultGenerator.genSuccessResult();
    }


    public Result genRoundLog(Tournament tournament ,Stage stage, List<TournamentTeam> tournamentUsers) {

        /**
         * 删除之前生成的
         */
        //删除round log
        roundLogMapper.deleteByByStageId(stage.getId());
        //删除round
        roundMapper.deleteByByStageId(stage.getId());
        stageRankMapper.deleteByStageId(stage.getId());

        /**
         * 自由模式
         */
        List<StageRank> stageRanks = new ArrayList<>();

        if(stage.getFormat()==GAME_FORMAT_FREE){
            /**
             * 不需要分配战队
             */
            //把报名的队伍copy 到 stage ——rank
            for (TournamentTeam tournamentUser : tournamentUsers) {
                StageRank rank = new StageRank();
                rank.setTournamentUserId(tournamentUser.getTournamentUserId());
                rank.setStageId(stage.getId());
                rank.setPromotion(false);
                rank.setGroubName("A");
                stageRanks.add(rank);
            }
        }


        /**
         * 循环赛模式
         */
        if(stage.getFormat()==GAME_FORMAT_ROUND) {

            if(tournamentUsers.size() < stage.getGroupSize() * 2){
                throw  new ServiceException("Insufficient number of participants");
            }

            int groupSize = tournamentUsers.size() / stage.getGroupSize();
            /**
             * 分组
             */
            for (int i = 0; i < tournamentUsers.size() ; i++) {
                logger.info(i%stage.getGroupSize()+"");
                tournamentUsers.get(i).setGroupName(GROUP_NAME[i%groupSize]);
                tournamentTeamMapper.updateByPrimaryKeySelective(tournamentUsers.get(i));
                //生成 stage_rank 信息
                StageRank rank = new StageRank();
                rank.setTournamentUserId(tournamentUsers.get(i).getTournamentUserId());
                rank.setStageId(stage.getId());
                rank.setPromotion(false);
                rank.setGroubName(tournamentUsers.get(i).getGroupName());
                stageRanks.add(rank);
            }

            Map<String, List<TournamentTeam>> group = tournamentUsers.stream().collect(Collectors.groupingBy(TournamentTeam::getGroupName));

            /**
             * 按组循环对打的次数
             */
            for (String g :group.keySet()) {
                List<RoundLog> roundLogs = new ArrayList<>();
                List<Round> rounds = new ArrayList<>();
                /**
                 * 循环队伍 和所有队伍对打一次
                 */
                //报名人数不是偶数加够偶数
                if (group.get(g).size() % 2 != 0) {
                    group.get(g).add(new TournamentTeam());
                }

                for (int x = 0; x < group.get(g).size()-1; x++) {
                    Round round = new Round();
                    round.setRoundName(String.valueOf(x));
                    round.setStageId(stage.getId());
                    round.setGourpName(g);
                    rounds.add(round);
                    roundMapper.insertSelective(round);
                    int bIndex = group.get(g).size() - rounds.size();
                    int aIndex = 0;
                    for (int y = 0; y < group.get(g).size() / 2; y++) {
                        //B对的下标
                        RoundLog log = new RoundLog();
                        //第二轮开始 先从后面分配
                        if(y>0 && rounds.size()>1 && y< rounds.size()){
                            if(rounds.size() < group.get(g).size() / 2){
                                log.setTournamentUserIdA(group.get(g).get(group.get(g).size() - rounds.size()+1).getTournamentUserId());
                            }else {
                                log.setTournamentUserIdA(group.get(g).get(group.get(g).size() - rounds.size()+y).getTournamentUserId());
                            }
                        }else {
                            log.setTournamentUserIdA(group.get(g).get(aIndex).getTournamentUserId());
                            aIndex++;
                        }
                        if(bIndex ==0){
                            bIndex = group.get(g).size()-1;
                        }
                        log.setTournamentUserIdB(group.get(g).get(bIndex).getTournamentUserId());
                        bIndex--;

                        log.setRoundId(round.getRoundId());
                        log.setType(1);
                        log.setStageId(stage.getId());
                        log.setGroupName(g);
                        roundLogs.add(log);
                    }
                }
                roundLogs.removeIf(log -> log.getTournamentUserIdB() == null || log.getTournamentUserIdA() == null);

                roundLogMapper.insertList(roundLogs);

            }
        }

        /**
         * 单败模式
         */
        if(stage.getFormat()==GAME_FORMAT_SINGLE) {
            int tournamentUserSize = tournamentUsers.size();
            //参赛人数必须是2的整数次幂
            double log = Math.log(tournamentUserSize)/Math.log(2);

            /**
             * 确定round数量
             */
            List<Round> rounds = new ArrayList<>();
            for (int i = 0; i < log ; i++) {
                Round round = new Round();
                round.setStageId(stage.getId());
                round.setRoundName(String.valueOf(i+1));
                round.setGourpName("A");
                roundMapper.insertSelective(round);
                rounds.add(round);
            }
            //第一轮的参赛队伍
            List<RoundLog> roundLogs = new ArrayList<>();

            //如果不够计算 第一轮的参赛队伍数量 和直接晋级下一轮的队伍
            if(Math.round(log) != log){
                //应该有多少队伍才够
                tournamentUserSize = (int) Math.pow(2,Math.ceil(log));

                int luckySize = tournamentUserSize - tournamentUsers.size();
                //直接晋级的队伍
                for ( int i = 0; i <luckySize ; i+=2) {
                    RoundLog roundLog = new RoundLog();
                    roundLog.setStageId(stage.getId());
                    roundLog.setTournamentUserIdA(tournamentUsers.get(i).getTournamentUserId());
                    if(luckySize > i+1){
                        roundLog.setTournamentUserIdB(tournamentUsers.get(i+1).getTournamentUserId());
                        roundLog.setLuckyBId(tournamentUsers.get(i+1).getTournamentUserId());

                    }
                    roundLog.setLuckyAId(tournamentUsers.get(i).getTournamentUserId());
                    //第二个round
                    roundLog.setRoundId(rounds.get(1).getRoundId());
                    roundLog.setType(1);
                    roundLogs.add(roundLog);
                }
                //空队伍放前面
                Collections.reverse(roundLogs);
                //第一轮参赛的队伍
                tournamentUserSize =  tournamentUsers.size() - luckySize;
                for ( int i = 0; i <tournamentUserSize ; i+=2) {
                    RoundLog roundLog = new RoundLog();
                    roundLog.setStageId(stage.getId());
                    roundLog.setTournamentUserIdA(tournamentUsers.get(i+luckySize).getTournamentUserId());
                    roundLog.setTournamentUserIdB(tournamentUsers.get(i+luckySize+1).getTournamentUserId());
                    //第一的round
                    roundLog.setRoundId(rounds.get(0).getRoundId());
                    roundLog.setType(1);
                    roundLogs.add(roundLog);
                }
                if(rounds.size()>2){
                    genRoundLog(roundLogs,(int) Math.pow(2,Math.ceil(log)),2,stage.getId(),rounds,1);
                }
            }
            else {
                
                for (int i = 0; i <tournamentUsers.size() ; i+=2) {
                    RoundLog roundLog = new RoundLog();
                    roundLog.setStageId(stage.getId());
                    roundLog.setTournamentUserIdA(tournamentUsers.get(i).getTournamentUserId());
                    roundLog.setTournamentUserIdB(tournamentUsers.get(i+1).getTournamentUserId());
                    roundLog.setRoundId(rounds.get(0).getRoundId());
                    roundLog.setType(1);
                    roundLogs.add(roundLog);
                }
                if(rounds.size()>1){
                    genRoundLog(roundLogs,(int) Math.pow(2,Math.ceil(log)),2, stage.getId(), rounds,1);
                }
            }

            roundLogMapper.insertList(roundLogs);
            //生成 stage_rank 信息
            for (TournamentTeam tournamentUser : tournamentUsers) {
                StageRank rank = new StageRank();
                rank.setTournamentUserId(tournamentUser.getTournamentUserId());
                rank.setStageId(stage.getId());
                rank.setPromotion(false);
                rank.setGroubName("A");
                stageRanks.add(rank);
            }
        }

        /**
         * 双败制
         */
        if(stage.getFormat() == GAME_FORMAT_DOUBLE){


            int tournamentUserSize = tournamentUsers.size();
            //参赛人数必须是2的整数次幂
            double log = Math.log(tournamentUserSize)/Math.log(2);

            /**
             * 确定胜者组round数量
             */
            List<Round> rounds = new ArrayList<>();
            for (int i = 0; i < log ; i++) {
                Round round = new Round();
                round.setStageId(stage.getId());
                round.setRoundName(String.valueOf(i));
                round.setGourpName("A");
                roundMapper.insertSelective(round);
                rounds.add(round);
            }

            /**
             *
             *胜者组round的数量*2-2-ROUND(胜者组round的数量-ROUNDDOWN(LOG(参数人数,2),1),0)
             */

            int loserRoundsSize= 3*2-2-(int) Math.round(3-BigDecimal.valueOf(log).setScale(1,BigDecimal.ROUND_HALF_UP).doubleValue());

            /**
             * 胜者组
             */
            //第一轮的参赛队伍
            List<RoundLog> roundLogs = new ArrayList<>();
            //如果不够计算第一轮的参赛队伍数量 和直接晋级下一轮的队伍
            if(Math.round(log) != log){
                tournamentUserSize = (int) Math.pow(2,Math.ceil(log));

                int luckySize = tournamentUserSize - tournamentUsers.size();
                //第二回合的对阵数量
                int luckySizeRound = tournamentUserSize/4;
                for (int i = 0; i <luckySizeRound ; i++) {
                    RoundLog roundLog = new RoundLog();
                    roundLog.setStageId(stage.getId());
                    if(luckySizeRound +i < luckySize ){
                        roundLog.setTournamentUserIdB(tournamentUsers.get(luckySizeRound +i).getTournamentUserId());
                        roundLog.setLuckyBId(tournamentUsers.get(luckySizeRound +i).getTournamentUserId());
                    }
                    if(i<luckySize){
                        roundLog.setTournamentUserIdA(tournamentUsers.get(i).getTournamentUserId());
                        roundLog.setLuckyAId(tournamentUsers.get(i).getTournamentUserId());
                    }
                    //第二的round
                    roundLog.setRoundId(rounds.get(1).getRoundId());
                    rounds.get(1).getLogs().add(roundLog);
                    roundLog.setType(1);
                    roundLogs.add(roundLog);
                }
                Collections.reverse(roundLogs);

                //第一轮参赛的队伍
                tournamentUserSize =  tournamentUsers.size() - luckySize;
                for (int i = 0; i <tournamentUserSize ; i+=2) {
                    RoundLog roundLog = new RoundLog();
                    roundLog.setStageId(stage.getId());
                    roundLog.setTournamentUserIdA(tournamentUsers.get(i+luckySize).getTournamentUserId());
                    roundLog.setTournamentUserIdB(tournamentUsers.get(i+luckySize+1).getTournamentUserId());
                    //第一的round
                    roundLog.setRoundId(rounds.get(0).getRoundId());
                    rounds.get(0).getLogs().add(roundLog);
                    roundLog.setType(1);
                    roundLogs.add(roundLog);
                }
                if(rounds.size()>2){
                    genRoundLog(roundLogs,(int) Math.pow(2,Math.ceil(log)),3,stage.getId(),rounds,1);
                }
            }
            else {
                for (int i = 0; i <tournamentUsers.size() ; i+=2) {
                    RoundLog roundLog = new RoundLog();
                    roundLog.setStageId(stage.getId());
                    roundLog.setTournamentUserIdA(tournamentUsers.get(i).getTournamentUserId());
                    roundLog.setTournamentUserIdB(tournamentUsers.get(i+1).getTournamentUserId());
                    roundLog.setRoundId(rounds.get(0).getRoundId());
                    rounds.get(0).getLogs().add(roundLog);
                    roundLog.setType(1);
                    roundLogs.add(roundLog);
                }
                if(rounds.size()>1){
                    genRoundLog(roundLogs,(int) Math.pow(2,Math.ceil(log)),2, stage.getId(), rounds,1);
                }
            }

            /**
             * 如果是双败制 胜者组需要增加一个回合
             */
            Round round = new Round();
            round.setStageId(stage.getId());
            round.setRoundName(String.valueOf(rounds.size()));
            round.setGourpName("A");
            roundMapper.insertSelective(round);
            rounds.add(round);

            RoundLog lastRoundLog = new RoundLog();
            lastRoundLog.setStageId(stage.getId());
            lastRoundLog.setRoundId(rounds.get(rounds.size()-1).getRoundId());
            rounds.get(rounds.size()-1).getLogs().add(lastRoundLog);
            lastRoundLog.setType(1);
            roundLogs.add(lastRoundLog);
            /**
             * 败者组
             */
            /**
             * 败者组round
             */
            List<Round> loserRounds =  new ArrayList<>();
            for (int i = 0; i < loserRoundsSize ; i++) {
                Round loserRound = new Round();
                loserRound.setStageId(stage.getId());
                loserRound.setRoundName(String.valueOf(i));
                loserRound.setGourpName("A");
                loserRound.setRoundType(2);
                roundMapper.insertSelective(loserRound);
                loserRounds.add(loserRound);
            }

            /**
             * 败者组参赛的队伍
             */
            int size = rounds.get(0).getLogs().size() + rounds.get(1).getLogs().size();
            double loserLog = Math.log(size)/Math.log(2);
            //理想的参赛人数
            int loserSize = (int) Math.pow(2,Math.ceil(loserLog));

            //第一回合的对阵数量
            int firstLogSize = (size - (loserSize - size)) /2;

            //第二回合的对阵数量
            int secRound = loserSize/4;

            /**
             * 不是刚好2的次方
             */
            if(Math.round(loserLog) != loserLog){
                /**
                 * 败者组第一个round的对阵
                 */
                for (int i1 = 0; i1 < firstLogSize; i1++) {
                    RoundLog roundLog = new RoundLog();
                    roundLog.setStageId(stage.getId());
                    roundLog.setRoundId(loserRounds.get(0).getRoundId());
                    roundLog.setGroupName("A");
                    roundLog.setType(2);
                    loserRounds.get(0).getLogs().add(roundLog);
                    roundLogs.add(roundLog);
                }

                for (int i = 1; i < loserRounds.size(); i++) {
                    //这个败者round 要有几次对阵
                    logger.warn(String.valueOf(secRound));

                    /**
                     * 如果败者组对阵是偶数 则每个偶数对阵 对阵数量减少一半  如果是奇数则每个奇数round对阵数量减少一半
                     */
                    if(loserRounds.size()%2==0){
                        if(i%2 == 0){
                            secRound  = secRound/2;
                        }
                    }else {
                        if(i%2 == 1){
                            secRound  = secRound/2;
                        }
                    }
                    for (int i1 = 0; i1 < secRound; i1++) {
                        RoundLog roundLog = new RoundLog();
                        roundLog.setStageId(stage.getId());
                        roundLog.setRoundId(loserRounds.get(i).getRoundId());
                        roundLog.setGroupName("A");
                        roundLog.setType(2);
                        //有连两条线的情况
                        if(loserRounds.get(i-1).getLogs().size() > secRound){

                            if(i1<loserRounds.get(i-1).getLogs().size() - secRound){
                                roundLog.setLuckyAId((long) i1*2);
                                roundLog.setLuckyBId((long) i1*2+1);
                            }else {
                                roundLog.setLuckyAId((long) i1+loserRounds.get(i-1).getLogs().size() - secRound);
                            }
                        }else {
                            if(loserRounds.get(i-1).getLogs().size()>i1){
                                roundLog.setLuckyAId((long) i1);
                            }
                        }
                        loserRounds.get(i).getLogs().add(roundLog);
                        roundLogs.add(roundLog);
                    }
                }

            }
            else {
                for (int i = 0; i < loserRounds.size(); i++) {
                    //这个败者round 要有几次对阵
                    logger.warn(String.valueOf(firstLogSize));
                    if(i%2 == 1){
                        firstLogSize  = firstLogSize/2;
                    }
                    for (int i1 = 0; i1 < firstLogSize; i1++) {
                        RoundLog roundLog = new RoundLog();
                        roundLog.setStageId(stage.getId());
                        roundLog.setRoundId(loserRounds.get(i).getRoundId());
                        roundLog.setGroupName("A");
                        if(i%2 == 1){
                            roundLog.setLuckyAId((long) i1*2);
                            roundLog.setLuckyBId((long) i1*2+1);
                        }
                        if(i%2 == 0 && i!=0) {
                            roundLog.setLuckyAId((long) i1);
                        }
                        roundLog.setType(2);
                        loserRounds.get(i).getLogs().add(roundLog);
                        roundLogs.add(roundLog);
                    }
                }

            }
            //生成 stage_rank 信息
            for (TournamentTeam tournamentUser : tournamentUsers) {
                StageRank rank = new StageRank();
                rank.setTournamentUserId(tournamentUser.getTournamentUserId());
                rank.setStageId(stage.getId());
                rank.setGroubName("A");
                rank.setPromotion(false);
                stageRanks.add(rank);
            }
            roundLogMapper.insertList(roundLogs);


        }
        stageRankMapper.insertList(stageRanks);

        return ResultGenerator.genSuccessResult();
    }

    /**
     * 生成空的对战信息
     * @param roundLogs
     * @param pow 参数总对数 2的次方
     * @param i 从地几轮开车生成
     * @param id
     * @param rounds
     */
    private void genRoundLog(List<RoundLog> roundLogs, int pow, int i, Long id, List<Round> rounds,int type) {
        Map<Long, List<RoundLog>> groupBySex = roundLogs.stream().collect(Collectors.groupingBy(RoundLog::getRoundId));
        //本轮对战次数
        for (int k = i-1; k < rounds.size() ; k++) {
             List<RoundLog> logs = groupBySex.get(rounds.get(k).getRoundId());
            int size = (int) (pow/(Math.pow(2,k+1)));
            if(logs!=null){
                size=  size - logs.size();; //2 4 8
             }
            for (int j = 0; j <size ; j++) {
                RoundLog roundLog = new RoundLog();
                roundLog.setStageId(id);
                roundLog.setRoundId(rounds.get(k).getRoundId());
                roundLog.setType(type);
                roundLogs.add(roundLog);
                rounds.get(k).getLogs().add(roundLog);
            }
        }
    }

    @Override
    public Result roundLog(Long stageId) {
        Stage stage = stageMapper.selectByPrimaryKey(stageId);
        Tournament tournament = tournamentMapper.selectByPrimaryKey(stage.getTournamentId());
        if(stage.getFormat().equals(GAME_FORMAT_FREE)){
            //自由模式返回所有参赛人员
            List<TournamentUserVo> vos = tournamentTeamMapper.selectByTournamentId(stage.getTournamentId(),tournament.getTournamentType(),false);
            return ResultGenerator.genSuccessResult(vos);
        }else {
            Map<String,Object> res = new HashMap<>();

            List<RoundLogVo> roundLogs = roundLogMapper.selectByStageId(stage.getId(),1,tournament.getTournamentType());

            List<RoundVo> rounds = roundMapper.selectVoByStageId(stageId,1);
            setLogToRound(rounds, roundLogs);
            if(stage.getFormat().equals(GAME_FORMAT_ROUND)){
                Map<String,List<RoundVo>> roundsGroup = rounds.stream().collect(Collectors.groupingBy(RoundVo::getGourpName));
                res.put("rounds",roundsGroup);
            }else {
                res.put("rounds",rounds);
            }

            res.put("log",roundLogs);
            if(stage.getFormat().equals(GAME_FORMAT_DOUBLE)){
                List<RoundVo> loserRounds = roundMapper.selectVoByStageId(stageId,2);
                List<RoundLogVo> loser = roundLogMapper.selectByStageId(stage.getId(),2,tournament.getTournamentType());
                setLogToRound(loserRounds, loser);
                res.put("loserRounds",loserRounds);
                res.put("loser",loser);
            }
            return ResultGenerator.genSuccessResult(res);
        }
    }

    private void setLogToRound(List<RoundVo> rounds, List<RoundLogVo> loser) {
        for (int i = 0; i < loser.size(); i++) {
            for (int i1 = 0; i1 < rounds.size(); i1++) {
                if(loser.get(i).getRoundId().equals(rounds.get(i1).getRoundId())){
                    rounds.get(i1).getRoundLogVos().add(loser.get(i));
                }
            }
        }
    }

    @Override
    public Result organization(Integer type, Integer status, String organizationName, AuthUser authUser, Integer page, Integer size, String order) {
        Map<String, Object> orderParams = JSONUtils.json2map(order);
        for (String key : orderParams.keySet()) {
            if (orderParams.get(key) != null && orderParams.get(key).equals("ascending")) orderParams.put(key, "asc");
            if (orderParams.get(key) != null && orderParams.get(key).equals("descending")) orderParams.put(key, "desc");
        }
        Map<String,Object> params = new HashMap<>();
        params.put("type",type);
        params.put("status",status);
        params.put("organizationName",organizationName);
        if(authUser.getType().equals(USER_ORGANIZATION)){
            ManageInfo manageInfo = manageInfoMapper.selectByPrimaryKey(authUser.getId());
            params.put("userId",manageInfo.getOrganizer());
        }
        PageHelper.startPage(page, size);
        List<TournamentListVo>  res = tournamentMapper.organizationList(params,orderParams);

        PageInfo<TournamentListVo> pageInfo = new PageInfo<>(res);
        Map<String,Object> result = new HashMap<>();

        result.put("list",pageInfo);
        Map<String, Object>  statistics= tournamentMapper.organizationStatistics(params);
        result.put("statistics",statistics);
        return ResultGenerator.genSuccessResult(result);
    }

    @Override
    public Result withdrawalApply(Long tournamentId, String bankName, String userName, String bankAccount) {
        Withdrawal withdrawal = withdrawalMapper.selectByTournament(tournamentId);
        if(withdrawal.getStatus() !=1){
            return  ResultGenerator.genFailResult(400,"Unable to apply");
        }
        withdrawal.setBankName(bankName);
        withdrawal.setUserName(userName);
        withdrawal.setBankAccount(bankAccount);
        withdrawal.setStatus(2);
        withdrawal.setCreateTime(new Date().getTime());
        withdrawalMapper.updateByPrimaryKey(withdrawal);
        return ResultGenerator.genSuccessResult();
    }

    @Override
    public Result agree(Long tournamentId, Integer status, String refuse, BigDecimal withdrawalProfit) {
        Withdrawal withdrawal = withdrawalMapper.selectByTournament(tournamentId);
        if(withdrawal.getStatus() !=2){
            return  ResultGenerator.genFailResult(400,"Unable to verify");
        }
        if(status == 3){
            withdrawal.setOrganizationProfit(withdrawalProfit);
        }
        if(status == 4){
            withdrawal.setRefuse(refuse);
        }
        withdrawal.setStatus(status);
        withdrawal.setCompleteTime(new Date().getTime());
        withdrawalMapper.updateByPrimaryKey(withdrawal);
        return ResultGenerator.genSuccessResult();
    }

    @Override
    public Result rewardList(Integer state, String hostName, String order, Integer page, Integer size) {
        Map<String, Object> orderParams = JSONUtils.json2map(order);
        for (String key : orderParams.keySet()) {
            if (orderParams.get(key) != null && orderParams.get(key).equals("ascending")) orderParams.put(key, "asc");
            if (orderParams.get(key) != null && orderParams.get(key).equals("descending")) orderParams.put(key, "desc");
        }
        PageHelper.startPage(page, size);
        orderParams.put("id","desc");
        List<TournamentListVo> tournamentListVos = tournamentMapper.rewardList(state,hostName,orderParams);
        for (TournamentListVo tournamentListVo : tournamentListVos) {
            List<TournamentReward> rewards = tournamentRewardMapper.selectByTournamentId(tournamentListVo.getId());
            tournamentListVo.setRewards(rewards);
        }
        PageInfo<TournamentListVo> pageInfo = new PageInfo<>(tournamentListVos);
        return ResultGenerator.genSuccessResult(pageInfo);
    }

    @Override
    public Result top(Long tournamentId, Boolean top) {

        int count = tournamentMapper.countTop();

        if(top && count>8){
            return ResultGenerator.genFailResult(400,"Can only pin maximum 8 tournaments");
        }

        Tournament tournament = findById(tournamentId);
        tournament.setHot(top);
        update(tournament);
        return ResultGenerator.genSuccessResult();
    }

    @Override
    public Result userlist(Integer state, Long gameId, String order, Integer page, Integer size, AuthUser user) {
        Map<String, Object> orderParams = JSONUtils.json2map(order);
        for (String key : orderParams.keySet()) {
            if (orderParams.get(key) != null && orderParams.get(key).equals("ascending")) orderParams.put(key, "asc");
            if (orderParams.get(key) != null && orderParams.get(key).equals("descending")) orderParams.put(key, "desc");
        }
        PageHelper.startPage(page, size);
        Map<String, Object> params = new HashMap<>();
        params.put("state", state);
        params.put("gameId", gameId);
        params.put("order", order);
        params.put("userID", user.getId());
        orderParams.put("hot", "desc");
        orderParams.put("id", "desc");
        List<TournamentUserListVo> res = tournamentMapper.userList(params, orderParams);

        PageInfo<TournamentUserListVo> pageInfo = new PageInfo<>(res);
        return ResultGenerator.genSuccessResult(pageInfo);
    }

    @Override
    public Result contestant(Long tournamentId) {
        List<ResultMap<String,Object>> contestant ;

       contestant =  tournamentTeamMapper.selectUserByTournamentId(tournamentId,true);
        return ResultGenerator.genSuccessResult(contestant);
    }

    @Override
    public Result rewardGrant(TournamentRewardUser rewardUser) {
        if(rewardUser.getId()!=null){
            tournamentRewardUserMapper.deleteByPrimaryKey(rewardUser);
            rewardUser.setId(null);
        }else {
           TournamentRewardUser user =  tournamentRewardUserMapper.selectUTR(rewardUser.getUserId(),rewardUser.getTournamentId(),rewardUser.getRewardId());
           if(user!=null){
               return  ResultGenerator.genFailResult(400,"Cannot be regenerate");
           }
            tournamentRewardUserMapper.insertSelective(rewardUser);
        }
        return ResultGenerator.genSuccessResult(rewardUser.getId());
    }

    @Override
    public Result grantConfirm(Long rewardId, Boolean confirm) {
        TournamentReward reward =  tournamentRewardMapper.selectByPrimaryKey(rewardId);
        reward.setGrantConfirm(confirm);
        tournamentRewardMapper.updateByPrimaryKeySelective(reward);
        return ResultGenerator.genSuccessResult();
    }

    @Override
    public Result checkin(Long tournamentId, Long userId) {
        Tournament tournament = findById(tournamentId);
        //报名中才可以签到
        if(tournament.getStatus()==2){
            TournamentTeam user;
            if(tournament.getTournamentType() == 0){
                user = tournamentTeamMapper.selectUserId(tournamentId,userId);
            }else {
                user = tournamentTeamMapper.selectTeamLeader(tournamentId,userId);
            }
            user.setCheckIn(true);
            user.setCheckInTime(new Date().getTime());
            tournamentTeamMapper.updateByPrimaryKeySelective(user);
            return ResultGenerator.genSuccessResult();
        }else {
            return ResultGenerator.genFailResult(400,"You have not registered for the tournaments, so cannot check in.");
        }
    }

    @Override
    public List<Map<String, Object>> analysis() {
        return tournamentTeamUserMapper.groupByState();
    }

    @Override
    public List<Tournament> listByStatus(int i) {
        return tournamentMapper.listByStatus(i);
    }

    @Override
    public List<TournamentTeamUserVo> joinUser(Long tournamentId) {
        return tournamentMapper.joinUser(tournamentId);
    }

    @Override
    public Result reset(Long tournamentId) {
        Tournament tournament = findById(tournamentId);
        List<TournamentTeam> tournamentUsers = tournamentTeamMapper.findByTournamentId(tournamentId,false);
        if(tournamentUsers.size()<2) return  ResultGenerator.genFailResult(400,"Insufficient number or participants");

        List<Stage> stages = stageMapper.selectByTournamentId(tournamentId);

        if(stages.get(0).getEnd()!=null){
            throw  new ServiceException("Tournament has started, cannot amend.");
        }

        if(tournament.getStatus() != 2 && tournament.getStatus() != 3 ){

            return ResultGenerator.genFailResult(400,"Tournament cannot be regenerated");
        }
        tournamentMapper.reset(tournamentId);
        /**
         * 打乱顺序后重新查
         */
        tournamentUsers = tournamentTeamMapper.findByTournamentId(tournamentId,false);
        for (int i = 0; i <stages.size() ; i++) {
            if(i==0){
                genRoundLog(tournament,stages.get(i),tournamentUsers);
            }else {
                List<TournamentTeam> tournamentUser = new ArrayList<>();
                //第二阶段参赛的人数
                int userSize = tournamentUsers.size() / stages.get(i-1).getGroupSize() * stages.get(i-1).getPromotionSize();
                for (int i1 = 0; i1 < userSize; i1++) {
                    tournamentUser.add(new TournamentTeam());
                }
                genRoundLog(tournament,stages.get(i),tournamentUser);
            }
        }

        return ResultGenerator.genSuccessResult();
    }

    @Override
    public Result updateTeam(Long tournamentId, Long teamId, AuthUser user, String[] userId) {

        UserInfo userInfo = userInfoMapper.selectByPrimaryKey(user.getId());

        //每次修改扣除80
        if(userInfo.getCoin().compareTo(new BigDecimal(80)) > 0){
            // 添加交易记录 扣除费用
            CoinTransaction transaction = new CoinTransaction();
            transaction.setAmountBalance(new BigDecimal(80).negate());
            transaction.setFromUserId(userInfo.getUserId());
            transaction.setOrderId(tournamentId);
            transaction.setRemark("Update Tournament Team");
            transaction.setTransactionTime(new Date().getTime());
            transaction.setTransactionType(COIN_TRANSACTION_TYPE_REGISTER);
            transaction.setCreateId(userInfo.getUserId());
            coinTransactionService.addOrSub(transaction);
        }else {
            return ResultGenerator.genFailResult(400,"");
        }

        List<TournamentTeam> tournamentUsers = tournamentTeamMapper.findByTournamentId(tournamentId,true);

        Tournament tournament = tournamentMapper.selectByPrimaryKey(tournamentId);

        if(tournamentUsers.size()>tournament.getParticipantsSize()){
            return ResultGenerator.genFailResult(400,"The number of participants is full");
        }

        if(tournament.getRegistrationTimeEnd() < new Date().getTime()){
            return ResultGenerator.genFailResult(400,"Exceeded the registration time");
        }

        /**
         * 1. Able to join free government tournaments ONLY
         * 只可以参与政府机构赛事
         *
         * 4. Able to join FREE rapid challenge
         * 只可以参加免费的对打
         */
        if(user.getLevel().equals(USER_LEVEL_BASE)){
            if(tournament.getRegisteryFee().compareTo(BigDecimal.ZERO) > 0 ){
                return ResultGenerator.genFailResult(400,"You can only join free rapid challenge");
            }

            if(!tournament.getTournamentCategory().equals(TOURNAMENT_CATEGORY_OFFICIALLY)){
                return ResultGenerator.genFailResult(400,"Your membership allow you to join only Bountee's free tournament. You can upgrade your membership to join this tournament.");
            }
        }

        if(tournament.getMode()!=null && tournament.getMode() != userId.length){
            return ResultGenerator.genFailResult(400,"The number of participants should be "+ tournament.getMode());
        }


        TournamentTeam  tournamentTeam = tournamentTeamMapper.selectOneByTeamId(teamId,tournamentId,true);

        //处理删除的用户
        List<TournamentTeamUser> tournamentTeamUsers = tournamentTeamUserMapper.selectByTeamIdAndTournamentId(teamId,tournamentId);
        List<TournamentTeamUser> remove = tournamentTeamUsers.stream().filter(tu -> !ArrayUtils.contains(userId,tu.getUserId().toString())).collect(Collectors.toList());
        for (int i = 0; i < remove.size(); i++) {
            int finalI = i;
            Arrays.asList(userId).removeIf(id -> id.equals(remove.get(finalI).getUserId().toString()));
            tournamentTeamUserMapper.deleteByTournamentIdAndUserId(remove.get(i).getTournamentTeamId(),remove.get(i).getUserId());
        }

        /**
         * 遍历报名用户
         */
        for (int i = 0; i <userId.length ; i++) {
            TournamentTeamUser oldUser = tournamentTeamUserMapper.selectByUidAndTournamentIdAndTournameTeamId(Long.parseLong(userId[i]),tournamentId,tournamentTeam.getTournamentUserId());
            if(oldUser!=null){
                //旧的不去处理
                logger.info("原有用户");
            }else {
                TournamentTeamUser users = tournamentTeamUserMapper.selectByUidAndTournamentId(Long.parseLong(userId[i]),tournamentId);
                if(users!=null) throw  new ServiceException("用户"+users.getUserId() + "已经报名该赛事");
                //新的新增
                TournamentTeamUser tournamentTeamUser = new TournamentTeamUser();
                tournamentTeamUser.setTournamentTeamId(tournamentTeam.getTournamentUserId());
                tournamentTeamUser.setUserId(Long.parseLong(userId[i]));

                UserInfo info =  userInfoMapper.selectByPrimaryKey(userId[i]);

                if(tournament.getOku()!=null&&tournament.getOku()&&(info.getOku()==null||!info.getOku())){
                    throw  new ServiceException(info.getFullName() + "本赛事有OKU限制");
                }
                if(tournament.getStudent()!=null&&tournament.getStudent()){
                    ResultMap<String,Object> identification= tournamentMapper.findIdentificationByUserType(Long.parseLong(userId[i]),"student");
                    if(identification==null){
                        throw  new ServiceException(info.getFullName() + "本赛事只能学生参加");
                    }
                }
                if(!StringUtils.isEmpty(tournament.getState())){
                    if(info.getAddressState()==null||!info.getAddressState().equals(tournament.getState())){
                        throw  new ServiceException(info.getFullName() + "本赛事只"+tournament.getState()+"参加");
                    }
                }
                if(!StringUtils.isEmpty(tournament.getEastWest())){
                    if(tournament.getEastWest().equals("east")&&!userIsEast(info)){
                        throw  new ServiceException(info.getFullName() + "本赛事只"+tournament.getEastWest()+"参加");
                    }
                    if(tournament.getEastWest().equals("west")&&!userIsWest(info)){
                        throw  new ServiceException(info.getFullName() + "本赛事只"+tournament.getEastWest()+"参加");
                    }
                }
                /**
                 * 完成任务
                 */
                taskService.completeTask("5",Long.parseLong(userId[i]),1);
                tournamentTeamUser.setRegisteryFee(new BigDecimal(0));
                tournamentTeamUser.setHandlingFee(new BigDecimal(0));
                tournamentTeamUserMapper.insert(tournamentTeamUser);
            }

        }

        /**
         *修改后需要重新报名
         */
        tournamentTeam.setCheckIn(false);
        tournamentTeamMapper.updateByPrimaryKeySelective(tournamentTeam);

        return ResultGenerator.genSuccessResult();
    }
}


